package com.yc.sole.erp.repository;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yc.sole.common.domain.StateCountResp;
import com.yc.sole.erp.dto.SaleOrderDto;
import com.yc.sole.erp.entity.SaleOrder;
import com.yc.sole.erp.enums.OrderState;
import com.yc.sole.erp.enums.PaymentState;
import com.yc.sole.erp.enums.ShipmentState;
import com.yc.sole.erp.exception.ErpResultEnum;
import com.yc.sole.erp.mapper.SaleOrderMapper;
import com.yc.sole.erp.request.SaleOrderQueryReq;
import com.yc.sole.framework.exception.BaseException;
import com.yc.sole.framework.mybatis.page.Paging;
import com.yc.sole.framework.mybatis.util.PageUtil;
import com.yc.sole.framework.result.BaseResultEnum;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 服务接口实现
 *
 * @author yizuomin
 * @date 2023-12-15
 **/
@Slf4j
@Service
@RequiredArgsConstructor
public class SaleOrderRepository extends ServiceImpl<SaleOrderMapper, SaleOrder> {

    /**
     * 新增
     *
     * @param saleOrderDto
     * @return RestResult
     */
    @Transactional(rollbackFor = Exception.class)
    public Long saveSaleOrder(SaleOrderDto saleOrderDto) {
        SaleOrder entity = new SaleOrder();
        BeanUtil.copyProperties(saleOrderDto, entity);
        this.save(entity);
        return entity.getId();
    }

    /**
     * 批量新增
     *
     * @param saleOrderDtos
     * @return RestResult
     */
    @Transactional(rollbackFor = Exception.class)
    public List<Long> saveSaleOrder(Collection<SaleOrderDto> saleOrderDtos) {
        List<SaleOrder> saleOrders = BeanUtil.copyToList(saleOrderDtos, SaleOrder.class);
        this.saveBatch(saleOrders);
        return saleOrders.stream().map(SaleOrder::getId).collect(Collectors.toList());
    }

    /**
     * 通过Id修改
     *
     * @param saleOrderDto
     * @return RestResult
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateSaleOrderById(SaleOrderDto saleOrderDto) {
        SaleOrder entity = new SaleOrder();
        BeanUtil.copyProperties(saleOrderDto, entity);
        this.updateById(entity);
    }

    /**
     * 通过id删除
     *
     * @param ids
     * @return RestResult
     */
    @Transactional(rollbackFor = Exception.class)
    public void deleteSaleOrder(Collection<Long> ids) {
        this.removeBatchByIds(ids);
    }

    /**
     * 根据id获取
     *
     * @param ids
     * @return RestResult
     */
    public List<SaleOrderDto> selectSaleOrderByIds(Collection<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return Collections.emptyList();
        }
        return BeanUtil.copyToList(this.listByIds(ids), SaleOrderDto.class);
    }

    /**
     * 根据id获取
     *
     * @param id
     * @return RestResult
     */
    public SaleOrderDto selectSaleOrderById(Long id) {
        return BeanUtil.copyProperties(this.getById(id), SaleOrderDto.class);
    }

    /**
     * 根据订单编号获取
     *
     * @param orderNo 订单编号
     * @return RestResult
     */
    public SaleOrderDto selectSaleOrderByOrderNo(String orderNo) {
        LambdaQueryWrapper<SaleOrder> wrapper = Wrappers.<SaleOrder>lambdaQuery().eq(SaleOrder::getOrderNo, orderNo);
        return BeanUtil.copyProperties(this.getOne(wrapper), SaleOrderDto.class);
    }

    /**
     * 根据订单编号获取
     *
     * @param orderNo 订单编号
     * @return RestResult
     */
    public List<SaleOrderDto> selectSaleOrderByOrderNoLike(String orderNo) {
        LambdaQueryWrapper<SaleOrder> wrapper = Wrappers.<SaleOrder>lambdaQuery()
                .like(CharSequenceUtil.isNotBlank(orderNo), SaleOrder::getOrderNo, orderNo);
        Page<SaleOrder> orderPage = new Page<>(1, 10);
        return BeanUtil.copyToList(this.page(orderPage, wrapper).getRecords(), SaleOrderDto.class);
    }

    /**
     * 分页查询
     *
     * @param page
     * @return RestResult
     */
    public Paging<SaleOrderDto> selectSaleOrderPage(Paging page, SaleOrderQueryReq saleOrderPageReq) {
        LambdaQueryWrapper<SaleOrder> wrapper = getWrapper(saleOrderPageReq);
        return PageUtil.pageCopy(this.page(PageUtil.toMybatisPage(page), wrapper), SaleOrderDto.class);
    }

    /**
     * 列表查询
     *
     * @param saleOrderPageReq
     * @return RestResult
     */
    public List<SaleOrderDto> selectSaleOrderList(SaleOrderQueryReq saleOrderPageReq) {
        LambdaQueryWrapper<SaleOrder> wrapper = getWrapper(saleOrderPageReq);
        return BeanUtil.copyToList(this.list(wrapper), SaleOrderDto.class);
    }

    /**
     * 构建查询条件
     *
     * @param queryReq
     * @return
     */
    private LambdaQueryWrapper<SaleOrder> getWrapper(SaleOrderQueryReq queryReq) {
        LambdaQueryWrapper<SaleOrder> wrapper = Wrappers.<SaleOrder>lambdaQuery()
                .like(CharSequenceUtil.isNotBlank(queryReq.getOrderNo()), SaleOrder::getOrderNo, queryReq.getOrderNo())
                .eq(CharSequenceUtil.isNotBlank(queryReq.getOrderDate()), SaleOrder::getOrderDate, queryReq.getOrderDate())
                .eq(Objects.nonNull(queryReq.getCustomerId()), SaleOrder::getCustomerId, queryReq.getCustomerId())
                .eq(Objects.nonNull(queryReq.getProductId()), SaleOrder::getProductId, queryReq.getProductId())
                .eq(Objects.nonNull(queryReq.getOrderState()), SaleOrder::getOrderState, queryReq.getOrderState())
                .eq(Objects.nonNull(queryReq.getPaymentState()), SaleOrder::getPaymentState, queryReq.getPaymentState())
                .eq(Objects.nonNull(queryReq.getPriority()), SaleOrder::getPriority, queryReq.getPriority())
                .eq(Objects.nonNull(queryReq.getShipmentState()), SaleOrder::getShipmentState, queryReq.getShipmentState())
                .in(CollUtil.isNotEmpty(queryReq.getPaymentStateList()), SaleOrder::getPaymentState, queryReq.getPaymentStateList())
                .in(CollUtil.isNotEmpty(queryReq.getOrderStateList()), SaleOrder::getOrderState, queryReq.getOrderStateList())
                .in(CollUtil.isNotEmpty(queryReq.getShipmentStateList()), SaleOrder::getShipmentState, queryReq.getShipmentStateList())
                .and(CharSequenceUtil.isNotBlank(queryReq.getKeyword()),
                        w -> w.like(SaleOrder::getProductName, queryReq.getKeyword())
                                .or().like(SaleOrder::getCustomerName, queryReq.getKeyword())
                                .or().like(SaleOrder::getOrderNo, queryReq.getKeyword())
                                .or().like(SaleOrder::getOrderDate, queryReq.getKeyword()))
                .orderByAsc(SaleOrder::getOrderState)
                .orderByDesc(SaleOrder::getPriority)
                .orderByDesc(SaleOrder::getId);
        if (CollUtil.isNotEmpty(queryReq.getOrderDateRange())
                && CharSequenceUtil.isNotBlank(queryReq.getOrderDateRange().get(0))
                && CharSequenceUtil.isNotBlank(queryReq.getOrderDateRange().get(1))) {
            wrapper.between(SaleOrder::getOrderDate, queryReq.getOrderDateRange().get(0), queryReq.getOrderDateRange().get(1));
        }
        return wrapper;
    }

    /**
     * 查询所有未完成的订单
     *
     * @return
     */
    public List<SaleOrderDto> selectAllUnFinishedOrder() {
        LambdaQueryWrapper<SaleOrder> wrapper = Wrappers.<SaleOrder>lambdaQuery().eq(SaleOrder::getOrderState, OrderState.PROCESSING);
        return BeanUtil.copyToList(this.list(wrapper), SaleOrderDto.class);
    }

    /**
     * 查询订单的产品单价
     *
     * @return
     */
    public Map<Long, List<SaleOrderDto>> selectOrderProductUnitPriceMap() {
        LambdaQueryWrapper<SaleOrder> wrapper = Wrappers.<SaleOrder>lambdaQuery()
                .select(SaleOrder::getProductId, SaleOrder::getUnitPrice)
                .in(SaleOrder::getOrderState, OrderState.UN_HANDLE, OrderState.PROCESSING, OrderState.COMPLETED);
        List<SaleOrderDto> saleOrderDtoList = BeanUtil.copyToList(this.list(wrapper), SaleOrderDto.class);
        return saleOrderDtoList.stream().collect(Collectors.groupingBy(SaleOrderDto::getProductId));
    }

    /**
     * 查询客户的所有金额
     *
     * @return
     */
    public Map<Long, BigDecimal> selectCustomerOrderAmount() {
        LambdaQueryWrapper<SaleOrder> wrapper = Wrappers.<SaleOrder>lambdaQuery()
                .select(SaleOrder::getCustomerId, SaleOrder::getAmount, SaleOrder::getPaidAmount)
                .in(SaleOrder::getPaymentState, PaymentState.PENDING, PaymentState.PARTIAL);
        List<SaleOrder> orderList = this.list(wrapper);
        return orderList.stream().collect(Collectors.groupingBy(SaleOrder::getCustomerId, Collectors.reducing(BigDecimal.ZERO, order -> order.getAmount().subtract(order.getPaidAmount() == null ? BigDecimal.ZERO : order.getPaidAmount()), BigDecimal::add)));
    }

    /**
     * 变更订单已支付金额
     *
     * @param orderId
     * @param updateAmount 变动金额 正数为加 负数为减
     */
    @Transactional(rollbackFor = Exception.class)
    public void updatePaidAmount(Long orderId, BigDecimal updateAmount) {
        if (updateAmount == null || BigDecimal.ZERO.compareTo(updateAmount) == 0) {
            return;
        }
        // 查询订单
        SaleOrderDto saleOrderDto = this.selectSaleOrderById(orderId);
        if (Objects.isNull(saleOrderDto)) {
            throw new BaseException(ErpResultEnum.SALE_ORDER_NOT_FOUND);
        }
        // 订单已付款金额
        BigDecimal newPaidAmount = saleOrderDto.getPaidAmount().add(updateAmount);
        if (newPaidAmount.compareTo(saleOrderDto.getAmount()) > 0) {
            throw new BaseException(ErpResultEnum.RECEIPT_AMOUNT_MORE_THAN_PAID_AMOUNT, newPaidAmount, saleOrderDto.getAmount());
        }
        if (newPaidAmount.compareTo(BigDecimal.ZERO) < 0) {
            throw new BaseException(ErpResultEnum.RECEIPT_AMOUNT_LESS_THAN_AMOUNT, newPaidAmount);
        }
        LambdaUpdateWrapper<SaleOrder> wrapper = Wrappers.<SaleOrder>lambdaUpdate()
                .eq(SaleOrder::getId, orderId)
                .eq(SaleOrder::getPaidAmount, saleOrderDto.getPaidAmount())
                .set(SaleOrder::getPaidAmount, newPaidAmount);
        // 若已支付金额等于订单金额，修改订单支付状态为已完成
        if (saleOrderDto.getAmount().compareTo(newPaidAmount) == 0) {
            wrapper.set(SaleOrder::getPaymentState, PaymentState.PAID);
        } else if (BigDecimal.ZERO.compareTo(newPaidAmount) == 0) {
            // 修改订单为待支付
            wrapper.set(SaleOrder::getPaymentState, PaymentState.PENDING);
        } else {
            // 修改订单为部分支付
            wrapper.set(SaleOrder::getPaymentState, PaymentState.PARTIAL);
        }
        // 若订单的发货状态为发货完成并且发货数量等于订单数量并且已完成付款，修改订单为已完成
        if (ShipmentState.SHIPPED.equals(saleOrderDto.getShipmentState())
                && saleOrderDto.getQuantity().equals(saleOrderDto.getShippedQuantity())
                && saleOrderDto.getAmount().compareTo(newPaidAmount) == 0) {
            wrapper.set(SaleOrder::getOrderState, OrderState.COMPLETED);
        } else {
            // 修改订单为处理中
            wrapper.set(SaleOrder::getOrderState, OrderState.PROCESSING);
        }
        boolean update = this.update(wrapper);
        if (!update) {
            throw new BaseException(BaseResultEnum.FAIL);
        }
    }

    /**
     * 变更已送货数量
     *
     * @param orderId
     * @param updateQuantity 变动数量 正数为加 负数为减
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateShippedQuantity(Long orderId, Integer updateQuantity) {
        if (updateQuantity == null || updateQuantity == 0) {
            return;
        }
        SaleOrderDto saleOrderDto = this.selectSaleOrderById(orderId);
        if (Objects.isNull(saleOrderDto)) {
            throw new BaseException(ErpResultEnum.SALE_ORDER_NOT_FOUND);
        }
        int newShippedQuantity = saleOrderDto.getShippedQuantity() + updateQuantity;
        if (newShippedQuantity > saleOrderDto.getQuantity()) {
            throw new BaseException(ErpResultEnum.SHIP_QUANTITY_MORE_THAN_ORDER_QUANTITY, newShippedQuantity, saleOrderDto.getQuantity());
        }
        LambdaUpdateWrapper<SaleOrder> wrapper = Wrappers.<SaleOrder>lambdaUpdate()
                .eq(SaleOrder::getId, orderId)
                .eq(SaleOrder::getShippedQuantity, saleOrderDto.getShippedQuantity())
                .set(SaleOrder::getShippedQuantity, newShippedQuantity);
        // 若发货数量=订单数量，修改订单发货状态为已发货
        if (saleOrderDto.getQuantity() == newShippedQuantity) {
            wrapper.set(SaleOrder::getShipmentState, ShipmentState.SHIPPED);
        } else if (saleOrderDto.getQuantity() > newShippedQuantity) {
            // 若定发货数量>0，修改发货状态为部分发货
            wrapper.set(SaleOrder::getShipmentState, ShipmentState.PARTIAL_SHIPPED);
        } else {
            // 若定发货数量=0，修改发货状态为待发货
            wrapper.set(SaleOrder::getShipmentState, ShipmentState.UN_SHIPPED);
        }
        // 若发货完成、并且已支付、修改订单为已完成
        if (saleOrderDto.getQuantity() == newShippedQuantity
                && saleOrderDto.getAmount().compareTo(saleOrderDto.getPaidAmount()) == 0
                && PaymentState.PAID.equals(saleOrderDto.getPaymentState())) {
            wrapper.set(SaleOrder::getOrderState, OrderState.COMPLETED);
        } else {
            wrapper.set(SaleOrder::getOrderState, OrderState.PROCESSING);
        }
        boolean update = this.update(wrapper);
        if (!update) {
            throw new BaseException(BaseResultEnum.FAIL);
        }
    }

    /**
     * 查询订单状态的数量
     *
     * @return
     */
    public List<StateCountResp> selectOrderStateCount(SaleOrderQueryReq queryReq) {
        return this.baseMapper.selectOrderStateCount(queryReq);
    }
}
